package com.example.OnlineStorage.service.User;

import com.example.OnlineStorage.Dao.UserDao;
import com.example.OnlineStorage.enums.GlobalVariables_String;
import com.example.OnlineStorage.exception.CustomException;
import com.example.OnlineStorage.pojo.Response.ResponseData;
import com.example.OnlineStorage.pojo.entity.Directory;
import com.example.OnlineStorage.pojo.entity.Node;
import com.example.OnlineStorage.pojo.entity.User;
import com.example.OnlineStorage.util.IO;
import com.example.OnlineStorage.util.Redis;
import com.example.OnlineStorage.util.SHA256;
import com.example.OnlineStorage.util.Verify;
import lombok.SneakyThrows;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.sql.SQLIntegrityConstraintViolationException;
import java.util.Objects;
import java.util.UUID;

/**
 * 用户服务接口的实现类，提供用户管理的基本操作。
 */
@Service
public class IUserService implements UserService {

    private final UserDao userDao;

    public IUserService(UserDao userDao) {
        this.userDao = userDao;
    }

    private User getUser(User user) {
        if (Redis.EXISTS(user.getUsername())) {
            String UUID = Redis.HGET(user.getUsername(), "UUID");
            logout(UUID);
        }
        // 生成并设置新的会话ID，将用户信息加密存储
        String token = UUID.randomUUID().toString();
        String username = user.getUsername();
        Redis.SET(token, username, 60 * 60 * 24);
        Redis.HSET(username, "user", user.toJson());
        Redis.HSET(username, "UUID", token);
        Redis.EXPIRE(username, 60 * 60 * 24);
        user.setPassword(null);
        return user;
    }

    /**
     * 更新用户信息并刷新会话。
     *
     * @param user 用户信息。
     * @param UUID 当前会话ID。
     * @return 更新后的用户信息。
     * @throws RuntimeException 如果更新失败。
     */
    private User getUser(User user, String UUID) {
        // 更新用户信息并验证更新是否成功
        try {
            if (this.userDao.update(user) > 0) {
                Redis.HSET(user.getUsername(), "user", user.toJson());
                Redis.EXPIRE(UUID, 60 * 30);
                Redis.EXPIRE(user.getUsername(), 60 * 30);
                return user;
            }
            throw new RuntimeException("信息更新失败");
        } catch (Exception e) {
            throw new RuntimeException("服务器异常");
        }


    }

    /**
     * 注册用户
     */
    @SneakyThrows
    @Override
    public User register(User user) {
        try {
            if (! Objects.equals(user.getUsername(), "")) {
                if (repeatUsername(user.getUsername())) {
                    throw new RuntimeException("用户名已存在.");
                }
            }
            if (! Objects.equals(user.getEmail(), "")) {
                if (repeatEmail(user.getEmail())) {
                    throw new RuntimeException("邮箱已存在.");
                }
            }
            Verify.VerifyRegisterUser(user);
            // 对密码进行SHA256加密
            user.setPassword(SHA256.calculateSha256Hash(user.getPassword()));
            Node root = new Directory("root", "/");
            user.setFileDataJson(root.toJson());
            userDao.insert(user);
            user.setPassword(null);
            return user;
        } catch (Exception e) {
            if (e.getCause() != null) {
                String Cause = e.getCause().toString();
                if (Cause.startsWith("java.sql.SQL")) {
                    throw new CustomException(500, "服务器异常,注册失败！");
                }
            }
            throw new CustomException(400, e.getMessage());
        }

    }

    /**
     * 用户名登录
     *
     * @param user 包含用户名和密码的用户信息。
     * @return 用户信息
     */
    @SneakyThrows
    @Override
    public User login_username(User user) {
        try {
            // 对密码进行SHA256加密
            user.setPassword(SHA256.calculateSha256Hash(user.getPassword()));
            User oldUser = this.userDao.loginByUsername(user);
            // 检查用户信息是否有效
            if (oldUser == null) {
                throw new RuntimeException("用户名或密码错误.");
            }
            return getUser(oldUser);
        } catch (Exception e) {
            if (e.getCause() != null) {
                String Cause = e.getCause().toString();
                if (Cause.startsWith("java.sql.SQL")) {
                    throw new CustomException(500, "服务器异常.请联系管理员.");
                }
            }
            throw new CustomException(400, e.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public User login_email(User user) {
        try {
            // 对密码进行SHA256加密
            user.setPassword(SHA256.calculateSha256Hash(user.getPassword()));
            User oldUser = this.userDao.loginByEmail(user);
            // 检查用户信息是否有效
            if (oldUser == null) {
                throw new RuntimeException("用户名或密码错误.");
            }
            return getUser(oldUser);
        } catch (Exception e) {
            if (e.getCause() != null) {
                String Cause = e.getCause().toString();
                if (Cause.startsWith("java.sql.SQL")) {
                    throw new CustomException(500, "服务器异常.请联系管理员.");
                }
            }
            throw new CustomException(400, e.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public User updateUser(User user, String UUID) {
        try {
            User oldUser = User.fromJson(Redis.HGET(Redis.GET(UUID), "user"));
            oldUser.setNickname(user.getNickname());
            return getUser(oldUser, UUID);
        } catch (RuntimeException e) {
            throw new CustomException(500, e.getMessage());
        }
    }

    /**
     * 更新用户头像，包括文件校验、存储和数据库信息更新。
     *
     * @param file       用户上传的头像文件。
     * @param fileSHA256 文件的SHA256校验值。
     * @param UUID       当前有效的会话ID。
     * @return 更新后的用户信息。
     */
    @SneakyThrows
    @Override
    public User putAvatar(MultipartFile file, String fileSHA256, String UUID) {
        String Path = null;
        boolean isDelPath = false;
        try {
            User user = User.fromJson(Redis.HGET(Redis.GET(UUID), "user"));
            String oldAvatar = user.getAvatarUrl();
            user.setAvatarUrl(fileSHA256);
            String type = IO.getFileType(file);
            if (!Verify.VerifyFileType_Image(type)) {
                throw new RuntimeException("文件类型，不允许");
            }
            String SHA_256 = SHA256.calculateFileSHA256(file);
            if (!fileSHA256.equals(SHA_256)) {
                throw new RuntimeException("文件在传输过程中出现异常.");
            }
            Path = GlobalVariables_String.File_Path_Avatar.getValue() + SHA_256;
            String oldAvatarPath = GlobalVariables_String.File_Path_Avatar.getValue() + oldAvatar;
            if (!IO.isFileExist(Path)) {
                IO.writeFile(file, Path);
            }
            if (this.userDao.selectAvatarCount(oldAvatar) == 1) {
                IO.deleteFile(oldAvatarPath);
            }
            if (this.userDao.selectAvatarCount(SHA_256) == 0) {
                isDelPath = true;
            }
            return getUser(user, UUID);

        } catch (Exception e) {
            if (isDelPath) {
                IO.deleteFile(Path);
            }
            if (e.getCause() != null) {
                String Cause = e.getCause().toString();
                if (Cause.startsWith("java.sql.SQL")) {
                    throw new CustomException(500, "服务器异常.请联系管理员.");
                }
            }
            throw new CustomException(400, e.getMessage());
        }
    }

    /**
     * 获取用户头像，如果未设置则返回默认头像。
     *
     * @param Avatar 用户头像的标识。
     * @return 包含头像文件和类型的响应体。
     */
    @SneakyThrows
    @Override
    public ResponseData getAvatar(String Avatar, String range) {
        try {
            long start = 0;
            if (range != null) {
                start = Long.parseLong(range.split("=")[1].split("-")[0]);
            }
            Avatar = !Avatar.isEmpty() ? Avatar : GlobalVariables_String.Avatar_Default.getValue();
            String path = GlobalVariables_String.File_Path_Avatar.getValue() + Avatar;
            return IO.onlineReadFile(path, start, range);
        } catch (RuntimeException e) {
            throw new CustomException(400, e.getMessage());
        }
    }

    /**
     * 更新用户密码，需要验证旧密码并确认新密码。
     *
     * @param oldPassword  用户当前密码。
     * @param newPassword  用户新密码。
     * @param newPassword2 新密码的确认。
     * @param UUID         当前有效的会话ID。
     */
    @SneakyThrows
    @Override
    public void updatePassword(String oldPassword, String newPassword, String newPassword2, String UUID) {
        User user = User.fromJson(Redis.HGET(Redis.GET(UUID), "user"));
        try {
            Verify.VerifyUpdatePassword(SHA256.calculateSha256Hash(oldPassword), newPassword, newPassword2, user);
            user.setPassword(SHA256.calculateSha256Hash(newPassword));
            if (this.userDao.updatePassword(user) > 0) {
                logout(UUID);
                return;
            }
            throw new Exception("服务器异常");
        } catch (Exception e) {
            if (e.getCause() != null) {
                String Cause = e.getCause().toString();
                if (Cause.startsWith("java.sql.SQL")) {
                    throw new CustomException(500, "服务器异常.请联系管理员.");
                }
            }
            throw new CustomException(400, e.getMessage());
        }
    }

    /**
     * 用户登出，清除会话信息。
     *
     * @param UUID 当前有效的会话ID。
     */
    @Override
    public void logout(String UUID) {
        String username = Redis.GET(UUID);
        Redis.DEL(UUID);
        Redis.DEL(username);
    }

    /**
     * 查询 username 是否重复
     *
     * @param username 要查询的username
     * @return 如果重复返回 true 否则 false
     */
    @SneakyThrows
    @Override
    public boolean repeatUsername(String username) {
        try {
            return userDao.repeatUsername(username) > 0;
        } catch (Exception e) {
            throw new CustomException(500, "数据库异常查询失败");
        }
    }

    /**
     * 查询 email 是否重复
     *
     * @param email 要查询的email
     * @return 如果重复返回 true 否则 false
     */
    @SneakyThrows
    @Override
    public boolean repeatEmail(String email) {
        try {
            return userDao.repeatEmail(email) > 0;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new CustomException(500, "数据库异常查询失败");
        }
    }
}
